#include<iostream>
#include<cstring>
#define MAXN 1000
using namespace std;

int cnt;
int head[MAXN];
int dist[MAXN];
int visi[MAXN];

typedef struct{
  int to;
  int next;
  int w;
}Edge;
Edge edge[MAXN*MAXN];

void Init();
void Add(int u,int v,int w);//add edge u->v
int Prim(int s,int n);

int main()
{
  int N,M;
  cin>>N>>M;
  Init();
  for(int i=0;i<M;i++){
    int s,e,w;
    cin>>s>>e>>w;
    Add(s,e,w);
    Add(e,s,w);//Fuck!!!一定记着添加两次我操
  }
  cout<<Prim(N,N)<<endl;
//  cout<<"cnt="<<cnt<<endl<<"n="<<N<<endl;
  return 0;
}

void Init()
{
  cnt=0;
  memset(head,-1,sizeof(head));
  memset(visi,0,sizeof(visi));
}
void Add(int u,int v,int w)//edge u->v
{
  edge[cnt].to=v;
  edge[cnt].w=w;
  edge[cnt].next=head[u];
  head[u]=cnt++;
}
int Prim(int s,int n)
{
  int num=1;//增加已经引入的点
  int now=s;
  int ans=0;

  for(int i=1;i<=n;i++){//初始化距离最大
    if(i!=now){
      dist[i]=0x3f3f3f3f;
    }
  }
  for(int i=head[now];i!=-1;i=edge[i].next){
    dist[edge[i].to]=min(edge[i].w,dist[edge[i].to]);
  }

  while(num<=n-1/*最小生成树n-1条边*/){
    int minn=0x3f3f3f3f;
    visi[now]=1;//从第1个点s开始，已经确定
    for(int i=1;i<=n;i++){//每次增加新边
        if(minn>dist[i]&&!visi[i]){
          minn=dist[i];
          now=i;
        }
    }
    ans+=minn;
    num++;//更新边
  for(int i=head[now];i!=-1;i=edge[i].next){//当前起点为now
    if(dist[edge[i].to]>edge[i].w&&!visi[edge[i].to]){
      dist[edge[i].to]=edge[i].w;
      }
    }
  }
  return ans;
}
